/*
	Software License Agreement (BSD License) 
	Copyright (c) 2008, OMNESOFT, L.L.C.
	All rights reserved.
	
	Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following 
	conditions are met:
	
	Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
	Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 
	in the documentation and/or other materials provided with the distribution.
	
	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
	NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
	THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
	OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.omnesoft.plugin.qb;

import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.Date;
import com.servoy.j2db.util.Debug;

import org.mozilla.javascript.NativeDate;

import ibizqb.Account;
import ibizqb.Address;
import ibizqb.Adjustinventory;
import ibizqb.Bill;
import ibizqb.Cccharge;
import ibizqb.Cccredit;
import ibizqb.Check;
import ibizqb.Company;
import ibizqb.Creditmemo;
import ibizqb.Customer;
import ibizqb.Deposit;
import ibizqb.Employee;
import ibizqb.Estimate;
import ibizqb.IBizQBException;
import ibizqb.Invoice;
import ibizqb.Item;
import ibizqb.Journalentry;
import ibizqb.Objsearch;
import ibizqb.Pricelevel;
import ibizqb.Purchaseorder;
import ibizqb.Qblists;
import ibizqb.Qbmsauthorize;
import ibizqb.Qbobject;
import ibizqb.Receivepayment;
import ibizqb.Salesorder;
import ibizqb.Salesreceipt;
import ibizqb.Timetracking;
import ibizqb.Vendor;

import com.servoy.j2db.plugins.IClientPluginAccess;
import com.servoy.j2db.scripting.IScriptObject;

public class QBProvider implements IScriptObject {

	@SuppressWarnings("unused")
	private IClientPluginAccess application;

	private QBConnection connection;

	public QBProvider(IClientPluginAccess arg0) {
		this.application = arg0;
	}

	@SuppressWarnings("unchecked")
	public Class[] getAllReturnedTypes() {
		return new Class[] { Account.class, Address.class,
				Adjustinventory.class, Bill.class, Cccharge.class,
				Cccredit.class, Check.class, Company.class, Creditmemo.class,
				Customer.class, Deposit.class, Employee.class, Estimate.class,
				Invoice.class, Item.class, Journalentry.class, Objsearch.class,
				Pricelevel.class, Purchaseorder.class, Qblists.class,
				Qbmsauthorize.class, Qbobject.class, Receivepayment.class,
				Salesorder.class, Salesreceipt.class, Timetracking.class,
				Vendor.class };
	}

	public String[] getParameterNames(String arg0) {
		if ("utilsQBDateToDate".equals(arg0)) {
			return new String[] { "qb_date_string" }; // e.g. '2008-10-08'
		} else if ("utilsDateToQBDate".equals(arg0)) {
			return new String[] { "js_date_obj" }; // Here Date is a NativeDate
		} else if ("openQBConnection".equals(arg0)) {
			return new String[] { "connection_string", "connection_mode",
					"use_ssl", "ssl_cert_path" };
		} else if ("Objsearch".equals(arg0)) {
			return new String[] { "queryType" };
		}
		

		return null;
	}

	public String getSample(String arg0) {

		// TODO: Write remaining samples
		if ("Account".equals(arg0)) {
			StringBuffer retval = new StringBuffer();

			retval.append("\t//\t" + getToolTip(arg0));
			retval.append("\n\n\t");
			retval.append("/*");
			retval.append("\n");
			retval
					.append("\t\tThe Account object manages QuickBooks accounts.\n\n"
							+ "\t\tRequired Fields (add): accountName, accountType\n"
							+ "\t\tSupported Methods: add, get (Id/Name), delete\n"
							+ "\t\tOnline Edition: Leave out isActive and bankNumber.\n\n"
							+ "\t\tWhen adding an account to QuickBooks, the important properties are accountName and accountType.\n"
							+ "\t\tIf desired, you may specify additional information such as parent *, isActive , accountNumber , bankNumber , and Description.\n"
							+ "\t\tYou may also specify an opening balance by setting openingBalance and openingBalanceDate.\n\n"
							+ "\t\tWhen retrieving account information from QuickBooks you may also retrieve the current balance.\n"
							+ "\t\tA variety of additional information about the account is available by calling config.");
			retval.append("\n\t");
			retval.append("*/");
			retval.append("\n\n");
			retval
					.append("\t// Sample code assumes Remote Connector is listening and that connection is established\n\n");
			retval.append("\tvar acct_obj = %%elementName%%.Account();\n");
			retval.append("\tacct_obj.accountName = 'ACME, Inc.';\n");
			retval
					.append("\tacct_obj.accountType = acct_obj.atIncome; // See IBiz documentation for a list of income type fields\n\n");
			retval.append("\ttry {\n");
			retval.append("\t\tacct_obj.add();\n");
			retval.append("\t} catch(e) {\n");
			retval
					.append("\t\tplugins.dialogs.showErrorDialog('Error', e, 'OK');\n");
			retval.append("\t}\n");
			retval.append("\n");

			return retval.toString();
		} else if ("Address".equals(arg0)) {
			StringBuffer retval = new StringBuffer();

			retval.append("\t//\t" + getToolTip(arg0));
			retval.append("\n\n\t");
			retval.append("/*");
			retval.append("\n");
			retval
					.append("\t\tAn Address object represents a geographical address.\n\n"
							+ "\t\tTo add an address to another object, such as a Customer , first instantiate an Address object, and set any or all of the properties: line1 , line2 , line3 , city , state , postalCode , and country."
							+ "\t\tThen, the Aggregate property may be used to construct an aggregate of the entire address. This aggregate should be passed to the other object.\n"
							+ "\t\tIn case you are using QuickBooks 2003 or above you may set line4 as well. (Be sure to set QBXMLVersion to 2.0 or above in any control to which the value of aggregate is copied.)");
			retval.append("\n\t");
			retval.append("*/");
			retval.append("\n\n");
			retval
					.append("\t// Sample code assumes Remote Connector is listening and that connection is established\n\n");
			retval.append("\tvar addr_obj = %%elementName%%.Address();\n");
			retval.append("\taddr_obj.city = 'Miami';\n");
			retval.append("\taddr_obj.state = 'FL';\n");
			retval
					.append("\tcustomer_obj.billingAddress = addr_obj.aggregate(); // Assumes customer_obj has already been initialized");
			retval.append("\n\n");
			retval
					.append("\t// The same process may be used in reverse to get an address from another object. For example, this pseudocode below will get the address of a Vendor:\n\n");
			retval
					.append("\tvendor_obj.get('ACME Inc.') // Assumes vendor_obj has already been initialized\n");
			retval.append("\taddr_obj.aggregate = vendor_obj.address");

			return retval.toString();
		} else if ("Objsearch".equals(arg0)) {
			StringBuffer retval = new StringBuffer();

			retval.append("\t//\t" + getToolTip(arg0));
			retval.append("\n\n\t");
			retval.append("/*");
			retval.append("\n");
			retval
					.append("\tAn Objsearch object represents a query into Quickbooks.\n\n" +
							"\t.If [queryType] is omitted as an argument you must call .setQueryType(int) before performing .search()\n" +
							"\tThe following is a table of the allowed [queryTypes] and their correcposing int values\n" +
							"\t\t Vendor \t-\t 1 \n" +
							"\t\t Employee \t-\t 2 \n" +
							"\t\t Bill \t-\t 3 \n" +
							"\t\t Invoice \t-\t 4 \n" +
							"\t\t CreditMemo \t-\t 5 \n" +
							"\t\t VendorCredit \t-\t 6 \n" +
							"\t\t SalesReceipt \t-\t 7 \n" +
							"\t\t PurchaseOrder \t-\t 8 \n" +
							"\t\t Check \t-\t 9 \n" +
							"\t\t CCCredit \t-\t 10 \n" +
							"\t\t CCCharge \t-\t 11 \n" +
							"\t\t Customer \t-\t 12 \n" +
							"\t\t Estimate \t-\t 13 \n" +
							"\t\t SalesOrder \t-\t 14 \n" +
							"\t\t TimeTracking \t-\t 15 \n" +
							"\t\t ReceivePayment \t-\t 16 \n" +
							"\t\t JournalEntry \t-\t 17 \n" +
							"\t\t Item \t-\t 18 \n" +
							"\t\t Account \t-\t 19 \n" +
							"\t\t Deposit \t-\t 20 \n" +
							"\t\t InventoryAdjustment \t-\t 21 \n" +
							"\t\t PriceLevel \t-\t 22 \n" +
							"\t\t Class \t-\t 23 \n" +
							"\t\t CustomerType \t-\t 24 \n" +
							"\t\t JobType \t-\t 25 \n" +
							"\t\t PaymentMethod \t-\t 26 \n" +
							"\t\t PayrollItemWage \t-\t 27 \n" +
							"\t\t SalesTaxCode \t-\t 28 \n" +
							"\t\t ShipMethod \t-\t 29 \n" +
							"\t\t SalesRep \t-\t 30 \n" +
							"\t\t VendorType \t-\t 31 \n" +
							"\t\t OtherTransaction \t-\t 100 \n" +
							"\t\t OtherList \t-\t 101 \n"
							);
			retval.append("\n\t");
			retval.append("*/");
			retval.append("\n\n");
			retval
					.append("\t// Sample code assumes Remote Connector is listening and that connection is established\n\n");
			retval.append("var oSearch = %%elementName%%.Objsearch('Vendor');\n");
			retval.append("oSearch.setNameContains('Test');\n");
			retval.append("oSearch.search();\n");
			retval.append("if (oSearch.getResultCount() == 0) { return false; }\n");
			retval.append("oVendor = %%elementName%%.Vendor();\n");
			retval.append("oVendor.setQBResponseAggregate(oSearch.getResultAggregate(0));\n");
			retval.append("application.output(oVendor.getVendorName());");
			
			return retval.toString();
		}
		return null;
	}

	public String getToolTip(String arg0) {

		// TODO: Write remaining tooltips
		if ("Account".equals(arg0)) {
			return "An Account object is used to represent QuickBooks accounts (such as Checking, Accounts Receivable, etc.)";
		} else if ("Address".equals(arg0)) {
			return "Address is a utility object which allows the user to easily edit and copy addresses. It is designed to interact with other beans, rather than QuickBooks.";
		} else if ("Objsearch".equals(arg0)) {
			return "Objsearch is the class used to perform queries in Quickbooks. If [queryType] is specified the appropriate value is set via setQueryType(int).";
		}

		return null;
	}

	public boolean isDeprecated(String arg0) {
		return false;
	}

	/*
	 * Simple wrappers for IBiz Integrator for QuickBooks "beans"
	 */
	public Account js_Account() {
		Account a = new Account();
		setConnectionInfoOnObject(a);
		return a;
	}

	public Address js_Address() {
		Address a = new Address();
		setConnectionInfoOnObject(a);
		return a;
	}

	public Adjustinventory js_Adjustinventory() {
		Adjustinventory a = new Adjustinventory();
		setConnectionInfoOnObject(a);
		return a;
	}

	public Bill js_Bill() {
		Bill b = new Bill();
		setConnectionInfoOnObject(b);
		return b;
	}

	public Cccharge js_Cccharge() {
		Cccharge c = new Cccharge();
		setConnectionInfoOnObject(c);
		return c;
	}

	public Cccredit js_Cccredit() {
		Cccredit c = new Cccredit();
		setConnectionInfoOnObject(c);
		return c;
	}

	public Check js_Check() {
		Check c = new Check();
		setConnectionInfoOnObject(c);
		return c;
	}

	public Company js_Company() {
		Company c = new Company();
		setConnectionInfoOnObject(c);
		return c;
	}

	public Creditmemo js_Creditmemo() {
		Creditmemo c = new Creditmemo();
		setConnectionInfoOnObject(c);
		return c;
	}

	public Customer js_Customer() {
		Customer c = new Customer();
		setConnectionInfoOnObject(c);
		return c;
	}

	public Deposit js_Deposit() {
		Deposit d = new Deposit();
		setConnectionInfoOnObject(d);
		return d;
	}

	public Employee js_Employee() {
		Employee e = new Employee();
		setConnectionInfoOnObject(e);
		return e;
	}

	public Estimate js_Estimate() {
		Estimate e = new Estimate();
		setConnectionInfoOnObject(e);
		return e;
	}

	public Invoice js_Invoice() {
		Invoice i = new Invoice();
		setConnectionInfoOnObject(i);
		return i;
	}

	public Item js_Item() {
		Item i = new Item();
		setConnectionInfoOnObject(i);
		return i;
	}

	public Journalentry js_Journalentry() {
		Journalentry j = new Journalentry();
		setConnectionInfoOnObject(j);
		return j;
	}

	public Objsearch js_Objsearch() {
		Objsearch o = new Objsearch();
		setConnectionInfoOnObject(o);
		return o;
	}
	
	public Objsearch js_Objsearch(String type) throws IBizQBException {
		Objsearch o = new Objsearch();
		setConnectionInfoOnObject(o);
		if (type.toLowerCase().equals("none")) 						{ o.setQueryType(0); }
		else if (type.toLowerCase().equals("vendor")) 				{ o.setQueryType(1); }
		else if (type.toLowerCase().equals("employee")) 			{ o.setQueryType(2); }
		else if (type.toLowerCase().equals("bill")) 				{ o.setQueryType(3); }
		else if (type.toLowerCase().equals("invoice")) 				{ o.setQueryType(4); }
		else if (type.toLowerCase().equals("creditmemo")) 			{ o.setQueryType(5); }
		else if (type.toLowerCase().equals("vendorcredit")) 		{ o.setQueryType(6); }
		else if (type.toLowerCase().equals("salesreceipt")) 		{ o.setQueryType(7); }
		else if (type.toLowerCase().equals("purchaseorder")) 		{ o.setQueryType(8); }
		else if (type.toLowerCase().equals("check")) 				{ o.setQueryType(9); }
		else if (type.toLowerCase().equals("cccredit")) 			{ o.setQueryType(10); }
		else if (type.toLowerCase().equals("cccharge")) 			{ o.setQueryType(11); }
		else if (type.toLowerCase().equals("customer")) 			{ o.setQueryType(12); }
		else if (type.toLowerCase().equals("estimate")) 			{ o.setQueryType(13); }
		else if (type.toLowerCase().equals("salesorder")) 			{ o.setQueryType(14); }
		else if (type.toLowerCase().equals("timetracking")) 		{ o.setQueryType(15); }
		else if (type.toLowerCase().equals("receivepayment")) 		{ o.setQueryType(16); }
		else if (type.toLowerCase().equals("journalentry")) 		{ o.setQueryType(17); }
		else if (type.toLowerCase().equals("item")) 				{ o.setQueryType(18); }
		else if (type.toLowerCase().equals("account")) 				{ o.setQueryType(19); }
		else if (type.toLowerCase().equals("deposit")) 				{ o.setQueryType(20); }
		else if (type.toLowerCase().equals("inventoryadjustment"))	{ o.setQueryType(21); }
		else if (type.toLowerCase().equals("pricelevel")) 			{ o.setQueryType(22); }
		else if (type.toLowerCase().equals("class")) 				{ o.setQueryType(23); }
		else if (type.toLowerCase().equals("customertype"))			{ o.setQueryType(24); }
		else if (type.toLowerCase().equals("jobtype")) 				{ o.setQueryType(25); }
		else if (type.toLowerCase().equals("paymentmethod")) 		{ o.setQueryType(26); }
		else if (type.toLowerCase().equals("payrollitemwage")) 		{ o.setQueryType(27); }
		else if (type.toLowerCase().equals("salestaxcode")) 		{ o.setQueryType(28); }
		else if (type.toLowerCase().equals("shipmethod")) 			{ o.setQueryType(29); }
		else if (type.toLowerCase().equals("salesrep")) 			{ o.setQueryType(30); }
		else if (type.toLowerCase().equals("vendortype")) 			{ o.setQueryType(31); }
		else if (type.toLowerCase().equals("othertransaction")) 	{ o.setQueryType(100); }
		else if (type.toLowerCase().equals("otherlist")) 			{ o.setQueryType(101); }
		else { return null; }
		return o;
	}
	

	public Pricelevel js_Pricelevel() {
		Pricelevel p = new Pricelevel();
		setConnectionInfoOnObject(p);
		return p;
	}

	public Purchaseorder js_Purchaseorder() {
		Purchaseorder p = new Purchaseorder();
		setConnectionInfoOnObject(p);
		return p;
	}

	public Qblists js_Qblists() {
		Qblists q = new Qblists();
		setConnectionInfoOnObject(q);
		return new Qblists();
	}

	public Qbmsauthorize js_Qbmsauthorize() {
		Qbmsauthorize q = new Qbmsauthorize();
		setConnectionInfoOnObject(q);
		return q;
	}

	public Qbobject js_Qbobject() {
		Qbobject q = new Qbobject();
		setConnectionInfoOnObject(q);
		return q;
	}

	public Receivepayment js_Receivepayment() {
		Receivepayment r = new Receivepayment();
		setConnectionInfoOnObject(r);
		return r;
	}

	public Salesorder js_Salesorder() {
		Salesorder s = new Salesorder();
		setConnectionInfoOnObject(s);
		return s;
	}

	public Salesreceipt js_Salesreceipt() {
		Salesreceipt s = new Salesreceipt();
		setConnectionInfoOnObject(s);
		return s;
	}

	public Timetracking js_Timetracking() {
		Timetracking t = new Timetracking();
		setConnectionInfoOnObject(t);
		return t;
	}

	public Vendor js_Vendor() {
		Vendor v = new Vendor();
		setConnectionInfoOnObject(v);
		return v;
	}

	public Boolean js_openQBConnection(String connectionString)
			throws IBizQBException {
		connection = new QBConnection();
		return connection.open(connectionString, 0, false, null);
	}

	public Boolean js_openQBConnection(String connectionString,
			Integer connectionMode) throws IBizQBException {
		connection = new QBConnection();
		return connection.open(connectionString, connectionMode, false, null);

	}

	public Boolean js_openQBConnection(String connectionString,
			Integer connectionMode, Boolean useSSL, String sslCertPath)
			throws IBizQBException {
		this.connection = new QBConnection();
		return connection.open(connectionString, connectionMode, useSSL,
				sslCertPath);

	}

	public Boolean js_closeQBConnection() throws IBizQBException {
		if (connection == null) {
			return false;
		} else {
			return connection.close();
		}
	}

	public String js_getQBConnectionString() {

		if (connection == null) {
			return null;
		}
		return connection.connectionString;
	}

	public Integer js_getQBConnectionMode() {
		if (connection == null) {
			return null;
		}
		return connection.connectionMode;
	}

	public NativeDate js_utilsQBDateToDate(String dateString)
			throws ParseException {
		return QBUtils.QBDateToDate(dateString);
	}

	public String js_utilsDateToQBDate(Date d) {
		return QBUtils.DateToQBDate(d);
	}

	private boolean setConnectionInfoOnObject(Object o) {
		// This method accepts an object from the ibizqdb package
		// And sets their connection info to match whatever is
		// currently set in the local QBConnection
		// Uses Reflection to find and execute the proper methods.

		if (connection == null)
		{
			return false;
		}
		else if (!(o.getClass().getPackage().getName().equals("ibizqb")))
		{
			Debug.error("Wrong package! " + o.getClass().getPackage().getName());
			return false;
		}
				
			

		try {

			Method setConnectionString = o.getClass().getMethod("setQBConnectionString", String.class);
			setConnectionString.invoke(o, connection.connectionString);

			Method setConnectionMode = o.getClass().getMethod("setQBConnectionMode", int.class);
			setConnectionMode.invoke(o, connection.connectionMode);
		} catch (Exception e) {
			Debug.error(e);
			return false;
		}
		return true;
	}

}
